/*******************************************************************************
* Project: QSAR(Cute Software Architecture) 
*
* Copyright: Copyright(C) 2024 by YuetingBen, All Rights Reserved
*
* File name: CanTp.c
*
* Brief: ;
*
* Author: Yueting.Ben
*
* Module: CanTp
*
*******************************************************************************/

/** HEADER FILES **/
#include "CanTp.h"


/** MACRO DEFINITION **/
#define N_PDU_SF_TYPE        0u
#define N_PDU_FF_TYPE        1u
#define N_PDU_CF_TYPE        2u
#define N_PDU_FC_TYPE        3u


#define N_PDU_SF_MAX_DATA_LEN      7u

/** TYPEDEF DEFINITION **/
typedef struct
{
    uint8 nPduType : 4;
    uint8 dataLength : 4;
    uint8 data[7];
}CanTpSignalFramePduType;


typedef struct
{
    uint16 nPduType : 4;
    uint8 dataLength : 12;
    uint8 data[6];
}CanTpFirstFramePduType;


typedef struct
{
    uint8 nPduType : 4;
    uint8 sn : 4;
    uint8 data[7];
}CanTpConsecutiveFramePduType;


typedef struct
{
    uint8 nPduType : 4;
    uint8 fs : 4;
    uint8 bs;
    uint8 stmin;
}CanTpFlowControlPduType;


typedef union
{
    CanTpSignalFramePduType signalFrame;
    CanTpFirstFramePduType firstFrame;
    CanTpConsecutiveFramePduType consecutiveFrame;
    CanTpFlowControlPduType flowControlFrame;
}CanTpPduType;

typedef enum
{
    CANTP_TXSTATE_IDLE = 0x00,
    CANTP_TXSTATE_TRANSMIT_SF,
    CANTP_TXSTATE_TRANSMIT_FF,
    CANTP_TXSTATE_WAIT_FC,
    CANTP_TXSTATE_RECEIVED_FC,
    CANTP_TXSTATE_TRANSMIT_CF,
    CANTP_TXSTATE_FINISHED  
}CanTpTxStateType;


typedef enum
{
    CANTP_RXSTATE_IDLE = 0x00,
    CANTP_RXSTATE_RECEIVED_SF,
    CANTP_RXSTATE_RECEIVED_FF,
    CANTP_RXSTATE_TRANSMIT_FC,
    CANTP_RXSTATE_WAIT_CF,
    CANTP_RXSTATE_RECEIVED_CF,
    CANTP_RXSTATE_FINISHED
}CanTpRxStateType;


typedef struct
{
    CanTpTxStateType CanTpTxState;
    uint8   CanTpTxSdu[8]; 
    uint8   TxRequestFlag;
    uint8  STmin;                   /* STmin */
    uint8  STminTimer;         /* timer for STmin */
    uint8  BlockSize;  /* block size */
    uint8  BlockSizeCnt;  
    uint16  TxTotalLength;
    uint16  TxTransferedLength;
    PduInfoType NPduInfo;
}CanTpTxInfoType;


typedef struct
{
    CanTpRxStateType CanTpRxState;
    uint8  CanTpRxSdu[8];
    uint8  RxIndicationFlag;
    uint16  RxTotalLength;
    uint16  RxReceivedLength;
    PduInfoType IPduInfo;
}CanTpRxInfoType;



/** LOCAL DATA DECLARATION **/
static CanTpTxInfoType CanTpTxInfo[CANTP_TX_ID_MAX];
static CanTpRxInfoType CanTpRxInfo[CANTP_RX_ID_MAX];

/** GLOBAL DATA DECLARATION **/


/** LOCAL FUNCTION DECLARATION **/
static void CanTpTransmitFC(
    PduIdType TxPduId
);


static void CanTpReceivedFC(
    PduIdType TxPduId,
    const PduInfoType* PduInfoPtr
);

static void CanTpTxHandle(
    CanTpTxIdType CanTpTxId
);

static void CanTpRxHandle(
    CanTpRxIdType CanTpRxId
);

/** GLOBAL FUNCTION DECLARATION **/
Std_ReturnType CanTp_Transmit(
    PduIdType TxPduId,
    const PduInfoType* PduInfoPtr
);

void CanTp_RxIndication(
    PduIdType RxPduId,
    const PduInfoType* PduInfoPtr
);

void CanTp_TxConfirmation(
    PduIdType TxPduId,
    Std_ReturnType result
);

void CanTp_Init(
    const CanTp_ConfigType* CfgPtr
);

void CanTp_MainFunction(void);


/** LOCAL DATA  **/
static CanTpTxInfoType CanTpTxInfo[CANTP_TX_ID_MAX] = {0};
static CanTpRxInfoType CanTpRxInfo[CANTP_RX_ID_MAX] = {0};


/** GLOBAL DATA  **/


/** LOCAL FUNCTION **/
static void CanTpTransmitFC(
    PduIdType TxPduId
)
{
    CanTpTxInfoType* canTpTxInfoPtr = &CanTpTxInfo[TxPduId];

    canTpTxInfoPtr->NPduInfo.SduDataPtr = canTpTxInfoPtr->CanTpTxSdu;
    canTpTxInfoPtr->NPduInfo.SduDataPtr[0] = 0x30;
    canTpTxInfoPtr->NPduInfo.SduLength = 8;

    CanIf_Transmit(CanTp_TxConfig[TxPduId].CanIfIndex, &canTpTxInfoPtr->NPduInfo);
}


static void CanTpReceivedFC(
    PduIdType TxPduId,
    const PduInfoType* PduInfoPtr
)
{
    CanTpTxInfoType* canTpTxInfoPtr = &CanTpTxInfo[TxPduId];

    if(CANTP_TXSTATE_WAIT_FC == canTpTxInfoPtr->CanTpTxState)
    {
        canTpTxInfoPtr->CanTpTxState = CANTP_TXSTATE_TRANSMIT_CF;
        canTpTxInfoPtr->BlockSize = PduInfoPtr->SduDataPtr[1];
        canTpTxInfoPtr->STmin = PduInfoPtr->SduDataPtr[2];
        canTpTxInfoPtr->STminTimer = 0u;
        canTpTxInfoPtr->BlockSizeCnt = 1u;
    }
}



static void CanTpTxHandle(
    CanTpTxIdType CanTpTxId
)
{
    CanTpTxInfoType* canTpTxInfoPtr = &CanTpTxInfo[CanTpTxId];
    PduLengthType bufferSize;
    RetryInfoType retry;
    uint8 i;
    
    switch(canTpTxInfoPtr->CanTpTxState)
    {
        case CANTP_TXSTATE_IDLE:
        {
            if(SET == canTpTxInfoPtr->TxRequestFlag)
            {
                canTpTxInfoPtr->TxRequestFlag = RESET;

                if(N_PDU_SF_MAX_DATA_LEN >= canTpTxInfoPtr->TxTotalLength)
                {
                    canTpTxInfoPtr->CanTpTxState = CANTP_TXSTATE_TRANSMIT_SF;
                }
                else
                {
                    canTpTxInfoPtr->CanTpTxState = CANTP_TXSTATE_TRANSMIT_FF;
                }
            }
            break;
        }
        case CANTP_TXSTATE_TRANSMIT_SF:
        {
            canTpTxInfoPtr->NPduInfo.SduDataPtr = &canTpTxInfoPtr->CanTpTxSdu[1];
            canTpTxInfoPtr->NPduInfo.SduLength = canTpTxInfoPtr->TxTotalLength;
            /* Padding */
            for(i = 0u; i < 8u; i++)
            {
                canTpTxInfoPtr->NPduInfo.SduDataPtr[i] = CanTpGeneral.CanTpPaddingByte;
            }
            
            PduR_CanTpCopyTxData(0, &canTpTxInfoPtr->NPduInfo, &retry, &bufferSize);
            canTpTxInfoPtr->CanTpTxSdu[0] = 0x00 | (canTpTxInfoPtr->NPduInfo.SduLength & 0x0F);
            
            canTpTxInfoPtr->NPduInfo.SduDataPtr = canTpTxInfoPtr->CanTpTxSdu;
            CanIf_Transmit(CanTp_TxConfig[CanTpTxId].CanIfIndex, &canTpTxInfoPtr->NPduInfo);
            canTpTxInfoPtr->CanTpTxState = CANTP_TXSTATE_FINISHED;
            break;
        }
        case CANTP_TXSTATE_TRANSMIT_FF:
        {
            canTpTxInfoPtr->NPduInfo.SduDataPtr = &canTpTxInfoPtr->CanTpTxSdu[2];
            canTpTxInfoPtr->NPduInfo.SduLength = 6;
            PduR_CanTpCopyTxData(0, &canTpTxInfoPtr->NPduInfo, &retry, &bufferSize);
            canTpTxInfoPtr->CanTpTxSdu[0] = 0x10 | ((canTpTxInfoPtr->TxTotalLength>> 8) & 0x0F);
            canTpTxInfoPtr->CanTpTxSdu[1] = (uint8)(canTpTxInfoPtr->TxTotalLength);
            
            canTpTxInfoPtr->NPduInfo.SduDataPtr = canTpTxInfoPtr->CanTpTxSdu;
            CanIf_Transmit(CanTp_TxConfig[CanTpTxId].CanIfIndex, &canTpTxInfoPtr->NPduInfo);
            canTpTxInfoPtr->TxTransferedLength += 6;
            canTpTxInfoPtr->CanTpTxState = CANTP_TXSTATE_WAIT_FC;
            break;
        }
        case CANTP_TXSTATE_WAIT_FC:
        {
            
            break;
        }
        case CANTP_TXSTATE_RECEIVED_FC:
        {
            break;
        }
        case CANTP_TXSTATE_TRANSMIT_CF:
        {
            if(canTpTxInfoPtr->STminTimer >= canTpTxInfoPtr->STmin)
            {
                canTpTxInfoPtr->STminTimer = 0u;
                canTpTxInfoPtr->NPduInfo.SduDataPtr = &canTpTxInfoPtr->CanTpTxSdu[1];
                canTpTxInfoPtr->NPduInfo.SduLength = 7;
                /* Padding */
                for(i = 0u; i < 8u; i++)
                {
                    canTpTxInfoPtr->NPduInfo.SduDataPtr[i] = CanTpGeneral.CanTpPaddingByte;
                }
                
                PduR_CanTpCopyTxData(0, &canTpTxInfoPtr->NPduInfo, &retry, &bufferSize);
    
                canTpTxInfoPtr->NPduInfo.SduDataPtr = canTpTxInfoPtr->CanTpTxSdu;
                CanIf_Transmit(CanTp_TxConfig[CanTpTxId].CanIfIndex, &canTpTxInfoPtr->NPduInfo);
                canTpTxInfoPtr->CanTpTxSdu[0] = 0x20 | (canTpTxInfoPtr->BlockSizeCnt & 0x0F);
                canTpTxInfoPtr->BlockSizeCnt++;
                canTpTxInfoPtr->TxTransferedLength += 7;
    
                if(canTpTxInfoPtr->TxTransferedLength >= canTpTxInfoPtr->TxTotalLength)
                {
                    canTpTxInfoPtr->CanTpTxState = CANTP_TXSTATE_FINISHED;
                }
                else
                {
                    canTpTxInfoPtr->CanTpTxState = CANTP_TXSTATE_TRANSMIT_CF;
                }
            }
            else
            {
                canTpTxInfoPtr->STminTimer++;
            }
        
            break;
        }
        case CANTP_TXSTATE_FINISHED:
        {
            canTpTxInfoPtr->TxTransferedLength = 0u;
            canTpTxInfoPtr->TxTotalLength = 0u;
            canTpTxInfoPtr->CanTpTxState = CANTP_TXSTATE_IDLE;
            break;
        }  
    }
}


static void CanTpRxHandle(
    CanTpRxIdType CanTpRxId
)
{
    CanTpRxInfoType* canTpRxInfoPtr = &CanTpRxInfo[CanTpRxId];
    
    switch(canTpRxInfoPtr->CanTpRxState)
    {
        case CANTP_RXSTATE_IDLE:
        {
            canTpRxInfoPtr->RxReceivedLength = 0u;
            canTpRxInfoPtr->RxTotalLength = 0u;
            
            break;
        }
        case CANTP_RXSTATE_RECEIVED_SF:
        {
            break;
        }
        case CANTP_RXSTATE_RECEIVED_FF:
        {

        }
        case CANTP_RXSTATE_TRANSMIT_FC:
        {
            CanTpTransmitFC(CANTP_RX_ID_0);
            canTpRxInfoPtr->CanTpRxState = CANTP_RXSTATE_WAIT_CF;
            break;
        }
        case CANTP_RXSTATE_WAIT_CF:
        {
            break;
        }
        case CANTP_RXSTATE_RECEIVED_CF:
        {
            break;
        }
        case CANTP_RXSTATE_FINISHED:
        {
            Dcm_TpRxIndication(0, 0);
            canTpRxInfoPtr->RxReceivedLength = 0u;
            canTpRxInfoPtr->RxTotalLength = 0u;
            canTpRxInfoPtr->CanTpRxState = CANTP_RXSTATE_IDLE;
            break;
        }
    }
}


/** GLOBAL FUNCTION **/
Std_ReturnType CanTp_Transmit(
    PduIdType TxPduId,
    const PduInfoType* PduInfoPtr
)
{
    CanTpTxInfoType* canTpTxInfoPtr = &CanTpTxInfo[TxPduId];
    
    canTpTxInfoPtr->TxRequestFlag = SET; 
    canTpTxInfoPtr->TxTotalLength = PduInfoPtr->SduLength;
    canTpTxInfoPtr->TxTransferedLength = 0u;
    
}


void CanTp_RxIndication(
    PduIdType RxPduId,
    const PduInfoType* PduInfoPtr
)
{
    uint8 nPduType;
    PduLengthType bufferSize;
    CanTpRxInfoType* canTpRxInfoPtr = &CanTpRxInfo[RxPduId];
    canTpRxInfoPtr->RxIndicationFlag = SET;

    //memcpy((uint8 *)(canTpRxInfoPtr->CanTpRxSdu), (uint8 *)(PduInfoPtr->SduDataPtr), PduInfoPtr->SduLength);

    nPduType = PduInfoPtr->SduDataPtr[0] >> 4;
    
    switch(canTpRxInfoPtr->CanTpRxState)
    {
            case CANTP_RXSTATE_IDLE:
            {
                if(N_PDU_SF_TYPE == nPduType)
                {
                    canTpRxInfoPtr->RxTotalLength= (PduLengthType)(PduInfoPtr->SduDataPtr[0] & 0x0F);
                    
                    canTpRxInfoPtr->IPduInfo.SduDataPtr = &PduInfoPtr->SduDataPtr[1];
                    canTpRxInfoPtr->IPduInfo.SduLength = 7;
                    PduR_CanTpStartOfReception(0, &canTpRxInfoPtr->IPduInfo, canTpRxInfoPtr->RxTotalLength, &bufferSize);
                    PduR_CanTpCopyRxData(0, &canTpRxInfoPtr->IPduInfo, &bufferSize);
                    canTpRxInfoPtr->CanTpRxState = CANTP_RXSTATE_FINISHED;
                }
                else if(N_PDU_FF_TYPE == nPduType)
                {
                    canTpRxInfoPtr->RxTotalLength = (PduLengthType)((PduInfoPtr->SduDataPtr[0] & 0x0F) << 8 | PduInfoPtr->SduDataPtr[1]);

                    canTpRxInfoPtr->IPduInfo.SduDataPtr = &PduInfoPtr->SduDataPtr[2];
                    canTpRxInfoPtr->IPduInfo.SduLength = 6;
                    PduR_CanTpStartOfReception(0, &canTpRxInfoPtr->IPduInfo, canTpRxInfoPtr->RxTotalLength, &bufferSize);

                    PduR_CanTpCopyRxData(0, &canTpRxInfoPtr->IPduInfo, &bufferSize);
                    canTpRxInfoPtr->RxReceivedLength += canTpRxInfoPtr->IPduInfo.SduLength;
                    canTpRxInfoPtr->CanTpRxState = CANTP_RXSTATE_TRANSMIT_FC;
                }
                else if(N_PDU_FC_TYPE == nPduType)
                {
                    canTpRxInfoPtr->IPduInfo.SduDataPtr = &PduInfoPtr->SduDataPtr[0];
                    canTpRxInfoPtr->IPduInfo.SduLength = 8;
                    CanTpReceivedFC(RxPduId, PduInfoPtr);
                }
                else
                {
                    /* Do nothing */
                }
                break;
            }
            case CANTP_RXSTATE_RECEIVED_SF:
            {}
            case CANTP_RXSTATE_RECEIVED_FF:
            {}
            case CANTP_RXSTATE_TRANSMIT_FC:
            {}
            case CANTP_RXSTATE_WAIT_CF:
            {
                if(N_PDU_CF_TYPE == nPduType)
                {
                    canTpRxInfoPtr->IPduInfo.SduDataPtr = &PduInfoPtr->SduDataPtr[1];
                    canTpRxInfoPtr->IPduInfo.SduLength = 7;

                    PduR_CanTpCopyRxData(0, &canTpRxInfoPtr->IPduInfo, &bufferSize);
                    canTpRxInfoPtr->RxReceivedLength += canTpRxInfoPtr->IPduInfo.SduLength;
                
                    if(canTpRxInfoPtr->RxReceivedLength >= canTpRxInfoPtr->RxTotalLength)
                    {
                        canTpRxInfoPtr->CanTpRxState = CANTP_RXSTATE_FINISHED;
                    }
                    else
                    {
                        canTpRxInfoPtr->CanTpRxState = CANTP_RXSTATE_WAIT_CF;
                    }
                }
                break;
            }
            case CANTP_RXSTATE_RECEIVED_CF:
            {}
            case CANTP_RXSTATE_FINISHED:
            {}
        }
}


void CanTp_TxConfirmation(
    PduIdType TxPduId,
    Std_ReturnType result
)
{

}


void CanTp_Init(
    const CanTp_ConfigType* CfgPtr
)
{
    
}


void CanTp_MainFunction (void)
{
    CanTpTxIdType canTpTxId;
    CanTpRxIdType canTpRxId;

    for(canTpTxId = CANTP_TX_ID_FIRST; canTpTxId < CANTP_TX_ID_MAX; canTpTxId++)
    {
        CanTpTxHandle(canTpTxId);
    }
    
    for(canTpRxId = CANTP_RX_ID_FIRST; canTpTxId < CANTP_RX_ID_MAX; canTpTxId++)
    {
        CanTpRxHandle(canTpRxId);
    }
}

